package com.gmall.common.util;


import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import com.gmall.common.constant.Constant;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.io.Encoders;
import io.jsonwebtoken.security.Keys;
import lombok.extern.slf4j.Slf4j;

import javax.crypto.SecretKey;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * jwt token
 *
 * @author HL.Wu
 * @date 2020/5/22 15:59
 * Copyright ©https://blog.csdn.net/qq_31150503 Copyright@2009-2020 AII Right Reserve
 */
@Slf4j
public class JwtUtil {

    /**
     * token header
     */
    public static final String TOKEN_HEADER = "Authorization";
    /**
     * token prefix
     */
    public static final String TOKEN_PREFIX = "Bearer ";
    /**
     * 过期时间
     */
    public static final long EXPIRATION = 1 * 24 * 60 * 60 * 1000L; // 2天
    /**
     * 选中记住密码 默认七天
     */
    public static final long EXPIRATION_REMEMBER = 604800L;

    public static String createToken(String userId,String username, Map<String, Object> map) {
        // add extra param
        boolean isRememberMe = (boolean) map.get(Constant.REMEMBER_ME);
        // create jwt token
        JwtBuilder jwtBuilder = Jwts.builder()
                .setClaims(map)
                .setIssuer(Constant.ISS)
                .setSubject(username)
                .setId(userId)
                .signWith(SignatureAlgorithm.HS256, Constant.JWT_SECRET);
        Date exp = getExpiredDate(isRememberMe);

        jwtBuilder.setExpiration(exp);

        //Builds the JWT and serializes it to a compact, URL-safe string
        return jwtBuilder.compact();
    }

    private static Date getExpiredDate(boolean isRememberMe) {
        //if it has been specified, let's add the expiration
        long expiration = isRememberMe ? EXPIRATION_REMEMBER : EXPIRATION;
        long expMillis = DateUtil.date().getTime() + expiration;
        return new Date(expMillis);
    }

    // method to validate and read the JWT
    public static Claims parseJWT(String token) {
        System.out.println("\n ");
        Claims claims;
        //This line will throw an exception if it is not a signed JWS (as expected)
        claims = Jwts.parser()
                .setSigningKey(Constant.JWT_SECRET)
                .parseClaimsJws(token).getBody();
        log.info("current token : [{}] \n ,expire time is [{}]",token,DateUtil.format(claims.getExpiration(), DatePattern.NORM_DATETIME_PATTERN));
        return claims;
    }

    /**
     * 自动刷新 每次请求自动刷新过期时间
     *
     * @param token
     */
    public static void autoRefreshAndDelayExpire(String token){
        // 每次请求 自动刷新token过期时间
        Claims claims = parseJWT(token);
        claims.setExpiration(getExpiredDate((Boolean) claims.get(Constant.REMEMBER_ME)));
        log.info("after refresh expired data is [{}]",DateUtil.format(claims.getExpiration(),DatePattern.NORM_DATETIME_PATTERN));
    }

    /**
     * 创建自定义 key
     *
     * @return
     */
    public static String createKey(){
        // create customize key
        SecretKey key = Keys.secretKeyFor(SignatureAlgorithm.HS256);
        String base64Key = Encoders.BASE64.encode(key.getEncoded());
        return base64Key;
    }

    /**
     * get user name by token
     *
     * @param token
     * @return
     */
    public static String getUsername(String token){
        // parse token
        Claims claims = parseJWT(token.replace(JwtUtil.TOKEN_PREFIX,""));
        return claims.getSubject();
    }

    /**
     * get user in the company Id
     *
     * @param token
     * @return
     */
    public static String getCompanyId(String token){
        // parse token
        Claims claims = parseJWT(token.replace(JwtUtil.TOKEN_PREFIX,""));
        if(claims.get(Constant.COMPANY_ID) == null){
            return "";
        }
        return (String) claims.get(Constant.COMPANY_ID);
    }

    /**
     * 获取用户id
     *
     * @param token
     * @return
     */
    public static String getUserId(String token){
        // parse token
        Claims claims = parseJWT(token.replace(JwtUtil.TOKEN_PREFIX,""));
        return claims.getId();
    }

    public static List<String> getRoles(String token){
        Claims claims = parseJWT(token);
        return (List<String>) claims.get("ROLE_CLAIMS");
    }

    /**
     * 校验token 是否过期
     *
     * @param token
     * @return
     */
    public static boolean isExpiration(String token){
        return parseJWT(token).getExpiration().before(DateUtil.date());
    }

    public static void main(String[] args) {
//        String jwt = createToken("sioo", null,false);
//        System.out.printf("JWT : \n" + jwt);
//        System.out.printf(""+ isExpiration("eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsImlzcyI6ImdtYWxsIiwiZXhwIjoxNTkxMDg3NTA5LCJqdGkiOiIxIiwiUk9MRV9DTEFJTVMiOlsiQWRtaW4iXSwiUkVNRU1CRVJfTUUiOmZhbHNlfQ.XFuycH7-7ECKx9f7AQoeVfg0t3J0NqCSKGuznF7NLLU"));
        System.out.println("-----------------------------------------");
        parseJWT("eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhZG1pbiIsImlzcyI6ImdtYWxsIiwiZXhwIjoxNTkxNzc5MTI1LCJqdGkiOiIxIiwiUk9MRV9DTEFJTVMiOlsiQWRtaW4iXSwiUkVNRU1CRVJfTUUiOmZhbHNlfQ.fkJZ1tSJ3bWrisJnXh0SLFpEWXbxNPw8fVbMaidBJX8");
        //autoRefreshAndDelayExpire("eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJzaW9vIiwiaXNzIjoiZ21hbGwiLCJleHAiOjE1OTA0MDQwNzcsIlJPTEVfQ0xBSU1TIjpudWxsLCJSRU1FTUJFUl9NRSI6ZmFsc2V9._qjh3ynbmBie6gbxaIYVPl-XCfkvzd6pRg_lpUcO6no");
    }
}
